package com.why.zing.payapi.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.why.zing.alipay.builder.AlipayTradePrecreateRequestBuilder;
import com.why.zing.alipay.builder.AlipayTradeQueryRequestBuilder;
import com.why.zing.alipay.builder.AlipayTradeRefundRequestBuilder;
import com.why.zing.alipay.result.AlipayF2FPrecreateResult;
import com.why.zing.alipay.result.AlipayF2FQueryResult;
import com.why.zing.alipay.result.AlipayF2FRefundResult;
import com.why.zing.alipay.service.AlipayTradeService;
import com.why.zing.common.utils.DateUtil;
import com.why.zing.common.utils.UuidGenerator;
import com.why.zing.payapi.constant.*;
import com.why.zing.payapi.entity.PayOrder;
import com.why.zing.payapi.exception.AliPayException;
import com.why.zing.payapi.exception.AliRefundException;
import com.why.zing.payapi.exception.RefundException;
import com.why.zing.payapi.model.*;
import com.why.zing.payapi.service.JobService;
import com.why.zing.payapi.service.OrderService;
import com.why.zing.payapi.service.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 订单处理
 *
 * @author 王洪玉
 * @date 2020年1月13日
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Value("${pay.alibaba.pid}")
    private String aliMerchantNo;

    @Autowired
    private AlipayTradeService alipayTradeService;

    @Autowired
    private PayOrderService payOrderService;

    @Autowired
    private JobService jobService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayOrderResponse aliPay(PayOrderRequest payOrderRequest) {

        PayOrder payOrder = new PayOrder();
        payOrder.setBusinessOrderNo(payOrderRequest.getBusinessOrderNo());
        payOrder.setOrderNo(UuidGenerator.generatorId());
        payOrder.setPayAmount(payOrderRequest.getTotalAmount());
        payOrder.setStatus(OrderStatusEnum.CREATE.getCode());
        payOrder.setTradeName(payOrderRequest.getTradeName());
        payOrder.setTradeDesc(payOrderRequest.getTradeDesc());
        payOrder.setPayType(PayTypeEnum.ALI_PAY.getCode());
        payOrder.setCallbackUrl(payOrderRequest.getCallbackUrl());
        // 支付超时，定义为30分钟
        int timeoutExpress = Constants.ALI_EXPIRE_TIME;
        if (payOrderRequest.getExpireTime() != null) {
            timeoutExpress = payOrderRequest.getExpireTime();
        }
        Date expireTime = DateUtil.addTime(timeoutExpress);
        payOrder.setExpireTime(expireTime);

        // 创建扫码支付请求builder，设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(payOrderRequest.getTradeName()).setTotalAmount(payOrderRequest.getTotalAmount().toPlainString()).setOutTradeNo(payOrder.getOrderNo())
                .setBody(payOrderRequest.getTradeDesc())
                .setStoreId(aliMerchantNo)
                .setTimeoutExpress(timeoutExpress + Constants.ALI_TIME_UNIT)
                //支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
                .setNotifyUrl(Constants.ALI_NOTIFY_URL);
        AlipayF2FPrecreateResult createResult = alipayTradeService.tradePrecreate(builder);
        if (!createResult.isTradeSuccess()) {
            throw new AliPayException(PayCodeEnum.ALI_PAY_ERROR);
        }

        PayOrderResponse payOrderResponse = new PayOrderResponse();
        payOrderResponse.setOrderNo(payOrder.getOrderNo());
        String qrCode = createResult.getResponse().getQrCode();
        payOrderResponse.setQrCode(qrCode);
        payOrder.setQrCode(qrCode);
        payOrderService.insertSelective(payOrder);

        jobService.addExpireOrderJob(payOrder.getOrderNo(), expireTime);
        return payOrderResponse;
    }


    /**
     * 查询订单
     *
     * @param orderNo 查询条件
     * @return 订单信息
     */
    @Override
    public OrderQueryResponse queryOrder(String orderNo) {

        PayOrder payOrder = new PayOrder();
        payOrder.setOrderNo(orderNo);
        payOrder = payOrderService.selectOne(payOrder);
        OrderQueryResponse orderQueryResponse = new OrderQueryResponse();
        BeanUtils.copyProperties(payOrder, orderQueryResponse);
        return orderQueryResponse;
    }


    /**
     * 申请退款
     *
     * @param orderRefundRequest 订单退款信息
     * @return 退款结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderRefundResponse refundOrder(OrderRefundRequest orderRefundRequest) {

        PayOrder payOrder = new PayOrder();
        payOrder.setOrderNo(orderRefundRequest.getOrderNo());
        PayOrder paidOrder = payOrderService.selectOne(payOrder);

        if (!StringUtils.equals(paidOrder.getStatus(), OrderStatusEnum.FINISH.getCode())) {
            throw new RefundException(PayCodeEnum.ORDER_NOT_IN_REFUND);
        }

        if (orderRefundRequest.getRefundAmount().compareTo(paidOrder.getPayAmount()) > 0) {
            throw new RefundException(PayCodeEnum.ORDER_REFUND_AMOUNT_ERROR);
        }

        PayOrder refundPayOrder = new PayOrder();
        refundPayOrder.setBusinessOrderNo(orderRefundRequest.getBusinessOrderNo());
        refundPayOrder.setOrderNo(UuidGenerator.generatorId());
        refundPayOrder.setPayAmount(orderRefundRequest.getRefundAmount());
        refundPayOrder.setStatus(OrderStatusEnum.CREATE.getCode());
        refundPayOrder.setTradeName(Constants.REFUND_NAME + paidOrder.getTradeName());
        refundPayOrder.setTradeDesc(orderRefundRequest.getRefundReason());
        refundPayOrder.setPayType(PayTypeEnum.ALI_PAY.getCode());
        refundPayOrder.setIsRefundOrder((byte) 1);
        refundPayOrder.setOriginalPayOrderId(paidOrder.getId());
        // 支付超时，定义为30分钟
        Date expireTime = DateUtil.addTime(Constants.ALI_EXPIRE_TIME);
        refundPayOrder.setExpireTime(expireTime);

        // 创建退款请求builder，设置请求参数
        AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder()
                .setOutTradeNo(orderRefundRequest.getOrderNo()).setRefundAmount(refundPayOrder.getPayAmount().toPlainString()).setRefundReason(refundPayOrder.getTradeDesc())
                .setStoreId(aliMerchantNo);

        AlipayF2FRefundResult result = alipayTradeService.tradeRefund(builder);
        if (!result.isTradeSuccess()) {
            throw new AliRefundException(result.getResponse().getSubCode(), result.getResponse().getSubMsg());
        }

        refundPayOrder.setStatus(OrderStatusEnum.REFUND_FINISH.getCode());
        payOrderService.insertSelective(refundPayOrder);

        // 更新原支付单状态
        PayOrder originPayOrder = new PayOrder();
        originPayOrder.setId(paidOrder.getId());
        originPayOrder.setTradeTime(new Date());
        originPayOrder.setStatus(OrderStatusEnum.REFUND.getCode());
        payOrderService.updatePayOrder(originPayOrder);

        OrderRefundResponse orderRefundResponse = new OrderRefundResponse();
        orderRefundResponse.setBusinessOrderNo(orderRefundRequest.getBusinessOrderNo());
        orderRefundResponse.setOrderNo(refundPayOrder.getOrderNo());
        orderRefundResponse.setStatus(OrderStatusEnum.REFUND_FINISH.getCode());
        return orderRefundResponse;
    }

    /**
     * 同步订单状态
     */
    @Override
    public void syncOrderStatus() {
        PayOrder payOrder = new PayOrder();
        payOrder.setStatus(OrderStatusEnum.CREATE.getCode());
        List<PayOrder> payOrderList = payOrderService.select(payOrder);
        payOrderList.forEach(pay -> {
            AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder()
                    .setOutTradeNo(pay.getOrderNo());
            AlipayF2FQueryResult result = alipayTradeService.queryTradeResult(builder);
            if (result.isTradeSuccess()) {
                PayOrder updatePayOrder = new PayOrder();
                AlipayTradeQueryResponse response = result.getResponse();
                updatePayOrder.setId(pay.getId());
                updatePayOrder.setStatus(OrderStatusEnum.FINISH.getCode());
                Date tradeTime = new Date();
                updatePayOrder.setTradeTime(tradeTime);
                updatePayOrder.setOutOrderNo(response.getTradeNo());
                payOrderService.updatePayOrder(updatePayOrder);

                OrderNotify orderNotifySuccess = assemblyOrderNotify(payOrder, updatePayOrder);
                jobService.addNotifyOrderJob(pay.getOrderNo(), pay.getCallbackUrl(), JSON.toJSONString(orderNotifySuccess));

                jobService.deleteJob(JobTypeEnum.EXPIRE_CLOSE_ORDER.getCode(),pay.getOrderNo());
            }
        });
    }


    private OrderNotify assemblyOrderNotify(PayOrder payOrder, PayOrder updatePayOrder) {
        OrderNotify orderNotify = new OrderNotify();
        orderNotify.setBusinessOrderNo(payOrder.getBusinessOrderNo());
        orderNotify.setOrderNo(payOrder.getOrderNo());
        orderNotify.setPayType(payOrder.getPayType());
        orderNotify.setStatus(updatePayOrder.getStatus());
        orderNotify.setOutOrderNo(updatePayOrder.getOutOrderNo());
        orderNotify.setPayAmount(payOrder.getPayAmount());
        if (updatePayOrder.getTradeTime() != null) {
            orderNotify.setTradeTime(DateUtil.date2StrByPattern(updatePayOrder.getTradeTime(), DateUtil.YYYY_MM_DD_HH_MM_SS));
        }
        return orderNotify;
    }


}
